
%{

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#include "common/log/log.h"
#include "common/lang/string.h"
#include "sql/parser/parse_defs.h"
#include "sql/parser/yacc_sql.hpp"
#include "sql/parser/lex_sql.h"
#include "sql/expr/expression.h"
#include "util/util.h"

using namespace std;

string token_name(const char *sql_string, YYLTYPE *llocp)
{
  return string(sql_string + llocp->first_column, llocp->last_column - llocp->first_column + 1);
}

int yyerror(YYLTYPE *llocp, const char *sql_string, ParsedSqlResult *sql_result, yyscan_t scanner, const char *msg)
{
  std::unique_ptr<ParsedSqlNode> error_sql_node = std::make_unique<ParsedSqlNode>(SCF_ERROR);
  error_sql_node->error.error_msg = msg;
  error_sql_node->error.line = llocp->first_line;
  error_sql_node->error.column = llocp->first_column;
  sql_result->add_sql_node(std::move(error_sql_node));
  return 0;
}

ArithmeticExpr *create_arithmetic_expression(ArithmeticExpr::Type type,
                                             Expression *left,
                                             Expression *right,
                                             const char *sql_string,
                                             YYLTYPE *llocp)
{
  ArithmeticExpr *expr = new ArithmeticExpr(type, left, right);
  expr->set_name(token_name(sql_string, llocp));
  return expr;
}

%}

%define api.pure full
%define parse.error verbose
/** 启用位置标识 **/
%locations
%lex-param { yyscan_t scanner }
/** 这些定义了在yyparse函数中的参数 **/
%parse-param { const char * sql_string }
%parse-param { ParsedSqlResult * sql_result }
%parse-param { void * scanner }

//标识tokens
%token  SEMICOLON
        CREATE
        DROP
        TABLE
        TABLES
        INDEX
        CALC
        SELECT
        INNER
        JOIN
        MAX
        MIN
        COUNT
        AVG
        SUM
        IS
        AS
        NOT
        LK
        IN
        EXIST
        DESC
        SHOW
        SYNC
        INSERT
        DELETE
        UPDATE
        LBRACE
        RBRACE
        COMMA
        TRX_BEGIN
        TRX_COMMIT
        TRX_ROLLBACK
        INT_T
        STRING_T
        FLOAT_T
        DATE_T
        NULL_T
        HELP
        EXIT
        DOT //QUOTE
        INTO
        VALUES
        FROM
        WHERE
        ORDER
        BY
        ASC
        UNIQUE
        AND
        OR
        SET
        ON
        LOAD
        DATA
        INFILE
        EXPLAIN
        EQ
        LT
        GT
        LE
        GE
        NE

/** union 中定义各种数据类型，真实生成的代码也是union类型，所以不能有非POD类型的数据 **/
%union {
  ParsedSqlNode *                   sql_node;
  ConditionSqlNode *                condition;
  Value *                           value;
  enum CompOp                       comp;
  UpdateInfo*                       update_info;
  std::vector<UpdateInfo>*          update_info_list;
  RelAttrSqlNode *                  rel_attr;
  JoinAttrSqlNode*                  join_attr;
  FuncSqlNode*                      func;
  std::vector<AttrInfoSqlNode> *    attr_infos;
  AttrInfoSqlNode *                 attr_info;
  Expression *                      expression;
  std::vector<Expression *> *       expression_list;
  std::vector<Value> *              value_list;
  std::vector<std::string>*         id_list;
  std::vector<ConditionSqlNode> *   condition_list;
  std::vector<RelAttrSqlNode> *     rel_attr_list;
  std::vector<JoinAttrSqlNode>*     join_attr_list;
  std::vector<FuncSqlNode> *        func_list;
  std::vector<OrderSqlNode>*        order;
  OrderSqlNode*                     order_sql_node;
  OrderType                         order_t;
  char *                            string;
  int                               number;
  float                             floats;
}

%token <number> NUMBER
%token <floats> FLOAT
%token <string> ID
%token <string> SSS
%token <string> DATE_STR
//非终结符

/** type 定义了各种解析后的结果输出的是什么类型。类型对应了 union 中的定义的成员变量名称 **/
%type <number>              type
%type <condition>           condition
%type <value>               value
%type <number>              number
%type <comp>                comp_op
%type<update_info>          update_info
%type<update_info_list>     update_info_list;
%type <rel_attr>            rel_attr
%type <join_attr>           join_attr
%type <func>                func
%type <number>              funcop
%type <attr_infos>          attr_def_list
%type <attr_info>           attr_def
%type <value_list>          value_list
%type <condition_list>      where
%type <condition_list>      condition_list
%type <order>               order
%type <order>               order_node_list;
%type <order_sql_node>      order_sql_node
%type <order_t>             order_t
%type <rel_attr_list>       select_attr
%type <join_attr_list>      join_list
%type <id_list>             id_list
%type<func_list>            func_list
%type <expression>          expression
%type <expression_list>     expression_list
%type <sql_node>            calc_stmt
%type <sql_node>            select_stmt
%type <sql_node>            insert_stmt
%type <sql_node>            update_stmt
%type <sql_node>            delete_stmt
%type <sql_node>            create_table_stmt
%type <sql_node>            drop_table_stmt
%type <sql_node>            show_tables_stmt
%type <sql_node>            desc_table_stmt
%type <sql_node>            create_index_stmt
%type <sql_node>            drop_index_stmt
%type <sql_node>            sync_stmt
%type <sql_node>            begin_stmt
%type <sql_node>            commit_stmt
%type <sql_node>            rollback_stmt
%type <sql_node>            load_data_stmt
%type <sql_node>            explain_stmt
%type <sql_node>            set_variable_stmt
%type <sql_node>            help_stmt
%type <sql_node>            exit_stmt
%type <sql_node>            command_wrapper
// commands should be a list but I use a single command instead
%type <sql_node>            commands

%left '+' '-'
%left '*' '/'
%nonassoc UMINUS
%%

commands: command_wrapper opt_semicolon  //commands or sqls. parser starts here.
  {
    std::unique_ptr<ParsedSqlNode> sql_node = std::unique_ptr<ParsedSqlNode>($1);
    sql_result->add_sql_node(std::move(sql_node));
  }
  ;

command_wrapper:
    calc_stmt
  | select_stmt
  | insert_stmt
  | update_stmt
  | delete_stmt
  | create_table_stmt
  | drop_table_stmt
  | show_tables_stmt
  | desc_table_stmt
  | create_index_stmt
  | drop_index_stmt
  | sync_stmt
  | begin_stmt
  | commit_stmt
  | rollback_stmt
  | load_data_stmt
  | explain_stmt
  | set_variable_stmt
  | help_stmt
  | exit_stmt
    ;

exit_stmt:      
    EXIT {
      (void)yynerrs;  // 这么写为了消除yynerrs未使用的告警。如果你有更好的方法欢迎提PR
      $$ = new ParsedSqlNode(SCF_EXIT);
    };

help_stmt:
    HELP {
      $$ = new ParsedSqlNode(SCF_HELP);
    };

sync_stmt:
    SYNC {
      $$ = new ParsedSqlNode(SCF_SYNC);
    }
    ;

begin_stmt:
    TRX_BEGIN  {
      $$ = new ParsedSqlNode(SCF_BEGIN);
    }
    ;

commit_stmt:
    TRX_COMMIT {
      $$ = new ParsedSqlNode(SCF_COMMIT);
    }
    ;

rollback_stmt:
    TRX_ROLLBACK  {
      $$ = new ParsedSqlNode(SCF_ROLLBACK);
    }
    ;

drop_table_stmt:    /*drop table 语句的语法解析树*/
    DROP TABLE ID {
      $$ = new ParsedSqlNode(SCF_DROP_TABLE);
      $$->drop_table.relation_name = $3;
      free($3);
    };

show_tables_stmt:
    SHOW TABLES {
      $$ = new ParsedSqlNode(SCF_SHOW_TABLES);
    }
    ;

desc_table_stmt:
    DESC ID  {
      $$ = new ParsedSqlNode(SCF_DESC_TABLE);
      $$->desc_table.relation_name = $2;
      free($2);
    }
    ;

create_index_stmt:    /*create index 语句的语法解析树*/
    CREATE INDEX ID ON ID LBRACE ID id_list RBRACE
    {
      $$ = new ParsedSqlNode(SCF_CREATE_INDEX);
      CreateIndexSqlNode &create_index = $$->create_index;
      create_index.index_name = $3;
      create_index.relation_name = $5;
      if($8!=nullptr){
      create_index.attribute_names.swap(*$8);
      }
      create_index.attribute_names.push_back($7);
      std::reverse(create_index.attribute_names.begin(),create_index.attribute_names.end());
      free($3);
      free($5);
      free($7);
      delete ($8);
    }
    |
    CREATE UNIQUE INDEX ID ON ID LBRACE ID id_list RBRACE{
      $$ = new ParsedSqlNode(SCF_CREATE_INDEX);

      CreateIndexSqlNode &create_index = $$->create_index;
      create_index.index_name = $4;
      create_index.relation_name = $6;
      if($9!=nullptr){
      create_index.attribute_names.swap(*$9);
      }
      create_index.attribute_names.push_back($8);
      std::reverse(create_index.attribute_names.begin(),create_index.attribute_names.end());
      create_index.is_unique=true;
      free($4);
      free($6);
      free($8);
      delete ($9);
    }
    ;
id_list:
  {
    $$=nullptr;
  }
  |
  COMMA ID id_list{
    if($3!=nullptr)$$=$3;
    else $$=new std::vector<std::string>;
    $$->push_back($2);
    free($2);
  }
drop_index_stmt:      /*drop index 语句的语法解析树*/
    DROP INDEX ID ON ID
    {
      $$ = new ParsedSqlNode(SCF_DROP_INDEX);
      $$->drop_index.index_name = $3;
      $$->drop_index.relation_name = $5;
      free($3);
      free($5);
    }
    ;
create_table_stmt:    /*create table 语句的语法解析树*/
    CREATE TABLE ID LBRACE attr_def attr_def_list RBRACE
    {
      $$ = new ParsedSqlNode(SCF_CREATE_TABLE);
      CreateTableSqlNode &create_table = $$->create_table;
      create_table.relation_name = $3;
      free($3);

      std::vector<AttrInfoSqlNode> *src_attrs = $6;

      if (src_attrs != nullptr) {
        create_table.attr_infos.swap(*src_attrs);
      }
      create_table.attr_infos.emplace_back(*$5);
      std::reverse(create_table.attr_infos.begin(), create_table.attr_infos.end());
      delete $5;
    }
    ;
attr_def_list:
    /* empty */
    {
      $$ = nullptr;
    }
    | COMMA attr_def attr_def_list
    {
      if ($3 != nullptr) {
        $$ = $3;
      } else {
        $$ = new std::vector<AttrInfoSqlNode>;
      }
      $$->emplace_back(*$2);
      delete $2;
    }
    ;
    
attr_def:
    ID type LBRACE number RBRACE NOT NULL_T %prec UMINUS{
      $$ = new AttrInfoSqlNode;
      $$->type = (AttrType)$2;
      $$->name = $1;
      $$->length = $4;
      $$->can_be_null=false;
      free($1);
    }
    |
    ID type LBRACE number RBRACE NULL_T %prec UMINUS{
      $$ = new AttrInfoSqlNode;
      $$->type = (AttrType)$2;
      $$->name = $1;
      $$->length = $4;
      $$->can_be_null=true;
      free($1);
    }
    |
    ID type LBRACE number RBRACE 
    {
      $$ = new AttrInfoSqlNode;
      $$->type = (AttrType)$2;
      $$->name = $1;
      $$->length = $4;
      free($1);
    }
    |
    ID type NULL_T %prec UMINUS{
      $$ = new AttrInfoSqlNode;
      $$->type = (AttrType)$2;
      $$->name = $1;
      $$->length = 4;
      $$->can_be_null=true;
      free($1);
    }
    |
    ID type NOT NULL_T %prec UMINUS{
       $$ = new AttrInfoSqlNode;
      $$->type = (AttrType)$2;
      $$->name = $1;
      $$->length = 4;
      $$->can_be_null=false;
      free($1);
    }
    | ID type
    {
      $$ = new AttrInfoSqlNode;
      $$->type = (AttrType)$2;
      $$->name = $1;
      $$->length = 4;
      free($1);
    }
    ;
number:
    NUMBER {$$ = $1;}
    ;
type:
    INT_T      { $$=INTS; }
    | STRING_T { $$=CHARS; }
    | FLOAT_T  { $$=FLOATS; }
    | DATE_T   { $$=DATES; }
    ;
insert_stmt:        /*insert   语句的语法解析树*/
    INSERT INTO ID VALUES LBRACE value value_list RBRACE 
    {
      $$ = new ParsedSqlNode(SCF_INSERT);
      $$->insertion.relation_name = $3;
      if ($7 != nullptr) {
        $$->insertion.values.swap(*$7);
      }
      $$->insertion.values.emplace_back(*$6);
      std::reverse($$->insertion.values.begin(), $$->insertion.values.end());
      delete $6;
      free($3);
    }
    ;

value_list:
    /* empty */
    {
      $$ = nullptr;
    }
    | COMMA value value_list  { 
      if ($3 != nullptr) {
        $$ = $3;
      } else {
        $$ = new std::vector<Value>;
      }
      $$->emplace_back(*$2);
      delete $2;
    }
    ;
value:
    NUMBER {
      $$ = new Value((int)$1);
      @$ = @1;
    }
    |FLOAT {
      $$ = new Value((float)$1);
      @$ = @1;
    }
    |SSS {
      char *tmp = common::substr($1,1,strlen($1)-2);
      $$ = new Value(tmp);
      free(tmp);
    }|DATE_STR {
      char *tmp_data  = nullptr;
      char *tmp = common::substr($1,1,strlen($1)-2);
      bool res = date_char2int(tmp,tmp_data);
      $$ = new Value(*(int*)tmp_data, res);
      delete[] tmp_data;
      free(tmp);
    }
    |NULL_T{
      $$=new Value();
      $$->set_null();
    }
    ;
    
delete_stmt:    /*  delete 语句的语法解析树*/
    DELETE FROM ID where 
    {
      $$ = new ParsedSqlNode(SCF_DELETE);
      $$->deletion.relation_name = $3;
      if ($4 != nullptr) {
        $$->deletion.conditions.swap(*$4);
        delete $4;
      }
      free($3);
    }
    ;
update_stmt:      /*  update 语句的语法解析树*/
    UPDATE ID SET update_info_list where 
    {
      $$ = new ParsedSqlNode(SCF_UPDATE);
      $$->update.relation_name = $2;
      if($4!=nullptr){
        $$->update.update_infos.swap(*$4);
      }
      if ($5 != nullptr) {
        $$->update.conditions.swap(*$5);
        delete $5;
      }
      free($2);
      
    }
    ;
update_info_list:
  update_info_list COMMA update_info{
    $$=$1;
    $$->push_back(*$3);
    delete $3;
  }
  |
  update_info {
    $$=new std::vector<UpdateInfo>;
    $$->push_back(*$1);
    delete $1;
  }
;
update_info:
  ID EQ value {
    $$=new UpdateInfo;
    $$->attribute_name=$1;
    $$->value=*$3;
    $$->is_value=true;
    delete $3;
    free($1);
  }
  |
  ID EQ LBRACE select_stmt RBRACE {
    $$=new UpdateInfo;
    $$->is_value=false;
    $$->attribute_name=$1;
    $$->sql=$4->selection;
    delete $4;
    free($1);
  }
  ;
select_stmt:        /*  select 语句的语法解析树*/
    SELECT select_attr FROM join_list where order{
      $$ = new ParsedSqlNode(SCF_SELECT);
      if ($2 != nullptr) {
        $$->selection.attributes.swap(*$2);
        delete $2;
      }
      if ($4 != nullptr) {
        $$->selection.joins.swap(*$4);
        delete $4;
      }
     
      if ($5 != nullptr) {
        $$->selection.conditions.swap(*$5);
        delete $5;
      }
      if($6!=nullptr){
        $$->selection.orders=*$6;
        delete $6;
      }
    }
    |
    SELECT func_list FROM join_list where order{
      $$ = new ParsedSqlNode(SCF_SELECT);
      if ($2 != nullptr) {
        $$->selection.funcs.swap(*$2);
        delete $2;
      }
      
      if ($4 != nullptr) {
        $$->selection.joins.swap(*$4);
        delete $4;
      }
      if ($5 != nullptr) {
        $$->selection.conditions.swap(*$5);
        delete $5;
      }
      if($6!=nullptr){
        $$->selection.orders=*$6;
        delete $6;
      }
    }
    |
    SELECT func_list COMMA select_attr FROM join_list where order %prec UMINUS
    {
      $$ = new ParsedSqlNode(SCF_SELECT);
      if ($2 != nullptr) {
        $$->selection.funcs.swap(*$2);
        delete $2;
      }
     
      if ($4 != nullptr) {
        $$->selection.attributes.swap(*$4);
        delete $4;
      }
      if ($6 != nullptr) {
        $$->selection.joins.swap(*$6);
        delete $6;
      }
      if ($7 != nullptr) {
        $$->selection.conditions.swap(*$7);
        delete $7;
      }
      if($8!=nullptr){
        $$->selection.orders=*$8;
        delete $8;
      }
    }
    |
    SELECT select_attr COMMA  func_list  FROM join_list where order %prec UMINUS
    {
      $$ = new ParsedSqlNode(SCF_SELECT);
      if ($4!= nullptr) {
        $$->selection.funcs.swap(*$4);
        delete $4;
      }
      if ($2 != nullptr) {
        $$->selection.attributes.swap(*$2);
        delete $2;
      }
      if ($6 != nullptr) {
        $$->selection.joins.swap(*$6);
        delete $6;
      }
     
      if ($7 != nullptr) {
        $$->selection.conditions.swap(*$7);
        delete $7;
      }
      if($8!=nullptr){
        $$->selection.orders=*$8;
        delete $8;
      }
    }
    ;
calc_stmt:
    CALC expression_list
    {
      $$ = new ParsedSqlNode(SCF_CALC);
      std::reverse($2->begin(), $2->end());
      $$->calc.expressions.swap(*$2);
      delete $2;
    }
    ;
func_list:
  func_list COMMA  func
  {
    if($1!=nullptr){
      $$=$1;
    }
    else {
      $$=new std::vector<FuncSqlNode>;
    }
    if($3!=nullptr){
    $$->push_back(*$3);
    delete $3;
    }
  }
  |
 func {
   $$=new std::vector<FuncSqlNode>;
   $$->push_back(*$1);
   delete $1;
  }
;
func:
  funcop LBRACE select_attr RBRACE{
    $$=new FuncSqlNode;
    $$->func_type=(FuncType)$1;
    if($3 != nullptr){
      $$->func_attributes.swap(*$3);
      delete $3;
    }
  }
  ;
funcop:
  MAX
  {
    $$=F_MAX;
  }
  |
  MIN
  {
    $$=F_MIN;
  }
  |
  COUNT
  {
    $$=F_COUNT;
  }
  |
  AVG 
  {
    $$=F_AVG;
  }
  |
  SUM
  {
    $$=F_SUM;
  };
order:
  {
    $$=nullptr;
  }
  |
  ORDER BY order_node_list{
    $$=$3;
  }
order_node_list:
  order_node_list COMMA order_sql_node{
    $$=$1;
    $$->push_back(*$3);
    delete $3;
  }
  |
  order_sql_node{
    $$=new std::vector<OrderSqlNode>;
    $$->push_back(*$1);
    delete $1;
  }
order_sql_node:
  rel_attr order_t
  {
    $$=new OrderSqlNode;
    $$->order_type=$2;
    if($1!=nullptr){
      $$->order_attribute=*$1;
      delete $1;
    }
  };
order_t:
  {
    $$=O_ASC;
  }
  |
  ASC
  {
    $$=O_ASC;
  }
  |
  DESC 
  {
    $$=O_DESC;
  }
expression_list:
    expression
    {
      $$ = new std::vector<Expression*>;
      $$->emplace_back($1);
    }
    | expression COMMA expression_list
    {
      if ($3 != nullptr) {
        $$ = $3;
      } else {
        $$ = new std::vector<Expression *>;
      }
      $$->emplace_back($1);
    }
    ;
expression:
    expression '+' expression {
      $$ = create_arithmetic_expression(ArithmeticExpr::Type::ADD, $1, $3, sql_string, &@$);
    }
    | expression '-' expression {
      $$ = create_arithmetic_expression(ArithmeticExpr::Type::SUB, $1, $3, sql_string, &@$);
    }
    | expression '*' expression {
      $$ = create_arithmetic_expression(ArithmeticExpr::Type::MUL, $1, $3, sql_string, &@$);
    }
    | expression '/' expression {
      $$ = create_arithmetic_expression(ArithmeticExpr::Type::DIV, $1, $3, sql_string, &@$);
    }
    | LBRACE expression RBRACE {
      $$ = $2;
      $$->set_name(token_name(sql_string, &@$));
    }
    | '-' expression %prec UMINUS {
      $$ = create_arithmetic_expression(ArithmeticExpr::Type::NEGATIVE, $2, nullptr, sql_string, &@$);
    }
    | value {
      $$ = new ValueExpr(*$1);
      $$->set_name(token_name(sql_string, &@$));
      delete $1;
    }
    ;

select_attr:
    select_attr  COMMA  rel_attr {
      if ($1 != nullptr) {
        $$ = $1;
      } else {
        $$ = new std::vector<RelAttrSqlNode>;
      }
      if($3!=nullptr){
      $$->emplace_back(*$3);
      delete $3;
      }
    }
    |
    rel_attr{
      $$=new std::vector<RelAttrSqlNode>;
      if($1!=nullptr){
        $$->emplace_back(*$1);
      delete $1;
      }
    }
    ;

rel_attr:
    ID {
      $$ = new RelAttrSqlNode;
      $$->attribute_name = $1;
      $$->has_alias=false;
      free($1);
    }
    |
    ID AS ID{
       $$ = new RelAttrSqlNode;
      $$->attribute_name = $1;
      $$->attribute_alias=$3;
      $$->has_alias=true;
      free($1);
      free($3);
    }
    | ID DOT ID {
      $$ = new RelAttrSqlNode;
      $$->relation_name  = $1;
      $$->attribute_name = $3;
      $$->attribute_alias=$3;
      $$->has_alias=false;
      free($1);
      free($3);
    }
    |
     ID DOT ID AS ID{
      $$ = new RelAttrSqlNode;
      $$->relation_name  = $1;
      $$->attribute_name = $3;
      $$->attribute_alias=$5;
      $$->has_alias=true;
      free($1);
      free($3);
      free($5);
    }
    |
    '*'
    {
      $$ = new RelAttrSqlNode;
      $$->relation_name  = "";
      $$->attribute_name = "*";
      $$->attribute_alias="*";
      $$->has_alias=false;
    }
    ;
join_attr:
  ID ON condition_list{
    $$=new JoinAttrSqlNode;
    $$->table_name=$1;
    $$->table_alias=$1;
    $$->have_conditions=false;
    $$->join_type=J_NONE;
    if($3!=nullptr){
      $$->conditions.swap(*$3);
      $$->have_conditions=true;
    }
    delete $3;
    free($1);
  }
  |
   ID AS ID ON condition_list{
    $$=new JoinAttrSqlNode;
    $$->table_name=$1;
    $$->table_alias=$3;
    $$->have_conditions=false;
    if($5!=nullptr){
      $$->conditions.swap(*$5);
      $$->have_conditions=true;
    }
    $$->join_type=J_NONE;
    delete $5;
    free($1);
    free($3);
  }
  |ID{
    $$=new JoinAttrSqlNode;
    $$->table_name=$1;
    $$->table_alias=$1;
    $$->have_conditions=false;
    $$->join_type=J_NONE;
    free($1);
  }
  |
  ID AS ID{
    $$=new JoinAttrSqlNode;
    $$->table_name=$1;
    $$->table_alias=$3;
    $$->have_conditions=false;
    $$->join_type=J_NONE;
    free($3);
  };
join_list:
  join_list INNER JOIN join_attr{
    $$=$1;
    JoinAttrSqlNode& last=$$->back();
    last.join_type=J_INNER;
    $$->push_back(*$4);
    delete $4;
  }
  |
  join_list COMMA join_attr
  {
    $$=$1;
    JoinAttrSqlNode& last=$$->back();
    last.join_type=J_NONE;
    $$->push_back(*$3);
    delete $3;
  }
  |
  join_attr{
    $$=new std::vector<JoinAttrSqlNode>;
    $$->push_back(*$1);
    delete $1;
  };
where:
    /* empty */
    {
      $$ = nullptr;
    }
    | WHERE condition_list {
      $$ = $2;  
      std::reverse($$->begin(),$$->end());
    }
    ;
condition_list:
    /* empty */
    {
      $$ = nullptr;
    }
    | condition {
      $$ = new std::vector<ConditionSqlNode>;
      $$->emplace_back(*$1);
      delete $1;
    }
    | condition AND condition_list {
      $$ = $3;
      $1->combination_type=C_AND;
      $$->emplace_back(*$1);
      delete $1;
    }
    | condition OR condition_list{
      $$ = $3;
      $1->combination_type=C_OR;
      $$->emplace_back(*$1);
      delete $1;
    }
    ;
condition:
    rel_attr comp_op value
    {
      $$ = new ConditionSqlNode;
      $$->left_type=C_ATTR;
      $$->left_attr = *$1;
      $$->right_type=C_VALUE;
      $$->right_value = *$3;
      $$->comp = $2;
      delete $1;
      delete $3;
    }
    | value comp_op value 
    {
      $$ = new ConditionSqlNode;
      $$->left_type=C_VALUE;
      $$->left_value = *$1;
      $$->right_type=C_VALUE;
      $$->right_value = *$3;
      $$->comp = $2;

      delete $1;
      delete $3;
    }
    | rel_attr comp_op rel_attr
    {
      $$ = new ConditionSqlNode;
      $$->left_type=C_ATTR;
      $$->left_attr = *$1;
      $$->right_type=C_ATTR;
      $$->right_attr = *$3;
      $$->comp = $2;

      delete $1;
      delete $3;
    }
    | value comp_op rel_attr
    {
      $$ = new ConditionSqlNode;
      $$->left_type=C_VALUE;
      $$->left_value = *$1;
      $$->right_type=C_ATTR;
      $$->right_attr = *$3;
      $$->comp = $2;

      delete $1;
      delete $3;
    }
    | rel_attr comp_op LBRACE select_stmt RBRACE
    {
      $$ = new ConditionSqlNode;
      if($1!=nullptr){
      $$->left_type=C_ATTR;
      $$->left_attr = *$1;
      }
      else
      {
        $$->left_type=C_NULL;
      }
      $$->right_type=C_SQL;
      $$->right_sql=new SelectSqlNode($4->selection);
      $$->comp = $2;
      delete $1;
      delete $4;
    }
    | value comp_op LBRACE select_stmt RBRACE
    {
      $$ = new ConditionSqlNode;
      $$->left_type=C_VALUE;
      $$->left_value = *$1;
      $$->right_type=C_SQL;
      $$->right_sql=new SelectSqlNode($4->selection);
      $$->comp = $2;
      delete $1;
      delete $4;
    }
    | LBRACE select_stmt RBRACE comp_op rel_attr
    {
      $$ = new ConditionSqlNode;
      $$->left_type=C_SQL;
      $$->left_sql = new SelectSqlNode($2->selection);
      $$->right_type=C_ATTR;
      $$->right_attr=*$5;
      $$->comp = $4;
      delete $2;
      delete $5;
    }
    | LBRACE select_stmt RBRACE comp_op value
    {
      $$ = new ConditionSqlNode;
      $$->left_type=C_SQL;
      $$->left_sql = new SelectSqlNode($2->selection);
      $$->right_type=C_VALUE;
      $$->right_value=*$5;
      $$->comp = $4;
      delete $2;
      delete $5;
    }
    | rel_attr comp_op LBRACE value value_list RBRACE{
      $$ = new ConditionSqlNode;
      if($1!=nullptr){
      $$->left_type=C_ATTR;
      $$->left_attr = *$1;
      }
      else {
        $$->left_type=C_NULL;
      }
      $$->right_type=C_VALUE_LIST;
      if($5!=nullptr){
      $$->right_value_list.swap(*$5);
      }
      $$->right_value_list.push_back(*$4);
      std::reverse($$->right_value_list.begin(), $$->right_value_list.end());
      $$->comp = $2;
      delete $1;
      delete $4;
      delete $5;
    }
    | value comp_op LBRACE value value_list RBRACE{
      $$ = new ConditionSqlNode;
      $$->left_type=C_VALUE;
      $$->left_value = *$1;
      $$->right_type=C_VALUE_LIST;
      if($5!=nullptr){
      $$->right_value_list.swap(*$5);
      }
      $$->right_value_list.push_back(*$4);
      std::reverse($$->right_value_list.begin(), $$->right_value_list.end());
      $$->comp = $2;
      delete $1;
      delete $4;
      delete $5;
    }
    |LBRACE value value_list RBRACE comp_op rel_attr{
      $$ = new ConditionSqlNode;
      $$->left_type=C_VALUE_LIST;
      if($3!=nullptr){
      $$->left_value_list.swap(*$3);
      }
      $$->left_value_list.push_back(*$2);
      std::reverse($$->left_value_list.begin(), $$->left_value_list.end());

      $$->right_type=C_ATTR;
      $$->right_attr = *$6;
      $$->comp = $5;
      delete $2;
      delete $3;
      delete $6;
    }
    | LBRACE value value_list RBRACE comp_op value{
      $$ = new ConditionSqlNode;
      $$->left_type=C_VALUE_LIST;
      if($3!=nullptr){
      $$->left_value_list.swap(*$3);
      }
      $$->left_value_list.push_back(*$2);
      std::reverse($$->left_value_list.begin(), $$->left_value_list.end());
      $$->right_type=C_VALUE;
      $$->right_value = *$6;
      $$->comp = $5;
      delete $2;
      delete $3;
      delete $6;
    }
    |
    LBRACE select_stmt RBRACE  comp_op LBRACE select_stmt RBRACE {
      $$=new ConditionSqlNode;
      $$->left_type=C_SQL;
      if($2!=nullptr){
        $$->left_sql=new SelectSqlNode($2->selection);
      }
      $$->right_type=C_SQL;
      if($6!=nullptr){
        $$->right_sql=new SelectSqlNode($6->selection);
      }
      $$->comp=$4;
      delete $2;
      delete $6;
    }
    ;

comp_op:
      EQ { $$ = EQUAL_TO; }
    | LT { $$ = LESS_THAN; }
    | GT { $$ = GREAT_THAN; }
    | LE { $$ = LESS_EQUAL; }
    | GE { $$ = GREAT_EQUAL; }
    | NE { $$ = NOT_EQUAL; }
    | LK {$$ = LIKE;}
    | NOT LK{$$=NOT_LIKE;}
    | IN {$$=_IN;}
    | NOT IN {$$=NOT_IN;}
    | EXIST {$$=_EXIST;}
    | NOT EXIST {$$=NOT_EXIST;}
    | IS {$$=_IS;}
    | IS NOT %prec UMINUS {$$=IS_NOT;}
    ;

load_data_stmt:
    LOAD DATA INFILE SSS INTO TABLE ID 
    {
      char *tmp_file_name = common::substr($4, 1, strlen($4) - 2);
      
      $$ = new ParsedSqlNode(SCF_LOAD_DATA);
      $$->load_data.relation_name = $7;
      $$->load_data.file_name = tmp_file_name;
      free($7);
      free(tmp_file_name);
    }
    ;

explain_stmt:
    EXPLAIN command_wrapper
    {
      $$ = new ParsedSqlNode(SCF_EXPLAIN);
      $$->explain.sql_node = std::unique_ptr<ParsedSqlNode>($2);
    }
    ;

set_variable_stmt:
    SET ID EQ value
    {
      $$ = new ParsedSqlNode(SCF_SET_VARIABLE);
      $$->set_variable.name  = $2;
      $$->set_variable.value = *$4;
      free($2);
      delete $4;
    }
    ;

opt_semicolon: /*empty*/
    | SEMICOLON
    ;
%%
//_____________________________________________________________________
extern void scan_string(const char *str, yyscan_t scanner);

int sql_parse(const char *s, ParsedSqlResult *sql_result) {
  yyscan_t scanner;
  yylex_init(&scanner);
  scan_string(s, scanner);
  int result = yyparse(s, sql_result, scanner);
  yylex_destroy(scanner);
  return result;
}
